Creating a Compound Widget

Widget primitives can be used to construct many varied user interfaces, but complex programs written with them suffer the following drawbacks:

Compound widgets solve these problems. A compound widget is a complete, self-contained, reusable widget sub-tree that behaves to a large degree just like a primitive widget. Complex widget applications written with compound widgets are much easier to maintain than the same application written without them. Using compound widgets is analogous to using subroutines and functions in programming languages.

Writing Compound Widgets

Compound widgets are written in the same way as any other widget application. They are distinguished from regular widget applications in the following ways:

For an example of how a compound widget might be written, see Example: Compound Widget.

The HANDLER Field of the Widget Event Structure

Recall that when WIDGET_EVENT finds an event to return, it moves up the widget hierarchy looking for an event-handling routine registered to the widgets in between its current position and the top-level base of the widget application. If such a routine is found, it is called with the event as its argument, and the HANDLER field of this event is set to the widget ID of the widget where the event routine was found. Since compound widgets have event handlers associated with their root widget, the HANDLER field gives the event handler the widget ID of the root widget. This allows the event handler for a compound widget instance to easily locate the location of its state information relative to this root.

Storing State Information

IDL programmers are often tempted to store the state information directly in the user value of the root widget, but this is not a good idea. The user value of a compound widget is reserved for the user of the widget, just like any basic widget. Therefore, you should store the state information in the user value of one of the child widgets below the root. As a convention, the user value of the first child is often used, leading to event handlers structured as follows:

FUNCTION EVENT_FUNC, event

  ; Get state from the first child of the compound widget root:

  child = WIDGET_INFO(event.HANDLER, /CHILD)

  WIDGET_CONTROL, child, GET_UVALUE=state, /NO_COPY

 

  ; Execute event-handling code here.

 

  ; Restore the state information before exiting routine:

  WIDGET_CONTROL, child, SET_UVALUE=state, /NO_COPY

 

  ; Return result of function

  RETURN, result

END

Sometimes, an application will find that it needs to use the user value of all its child widgets for some other purpose, and there is no convenient place to keep the state information. One way to work around this problem is to interpose an extra base between the root base and the rest of the widgets:

ROOT = WIDGET_BASE(parent)

EXTRA = WIDGET_BASE(root)

In such an approach, the remaining widgets would all be children of EXTRA rather than ROOT.